package com.dly.hope.servce.impl;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import com.dly.hope.constant.ExceptionConstant;
import com.dly.hope.servce.JwtService;
import com.dly.hope.utils.ExceptionPropertiesUtil;
import com.dly.hope.utils.JsonFormatUtil;
import com.dly.hope.vo.UserDTO;
import io.vavr.control.Try;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @author linyu.dai
 * @project myserve
 * @description jwt实现类
 * @creat 2022/8/26 23:45:25
 */
@Service
@Slf4j
public class JwtServiceImpl implements JwtService {

    /**
     * 秘钥
     */
    @Value("${jwt.secret}")
    private  String secret;

    /**
     * 过期时间
     **/
    @Value("${jwt.expireTime}")
    private  long expireTime;//单位为秒

    /**
     * 文件过期时间
     **/
    @Value("${file.load.expireTime}")
    private long fileExpireTime;//单位为秒

    @Override
    public String sign(UserDTO userDTO) {
        //过期时间
        Date expireDate = new Date(System.currentTimeMillis() + expireTime * 1000);

        Map<String, Object> map = new HashMap<>();
        map.put("alg", "HS256");
        map.put("typ", "JWT");

        return JWT.create()
                .withHeader(map)                    //添加头部
                //可以把数据存在claim中
                .withClaim("date", JsonFormatUtil.writeToJson(userDTO))
                .withExpiresAt(expireDate)          //超时设置,设置过期的日期
                .withIssuedAt(new Date())           //签发时间
                .sign(Algorithm.HMAC256(secret));
    }
    @Override
    public UserDTO unSign(String token) {

        return Try.of(() -> {
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(secret)).build();
            DecodedJWT jwt = verifier.verify(token);
            String date = jwt.getClaim("date").asString();
            return JsonFormatUtil.readFromJsonString(date, UserDTO.class);
        }).onFailure((e) -> {
            log.error(ExceptionPropertiesUtil.getMsg(ExceptionConstant.TOKEN_EXPIRED));
        }).getOrElseThrow(() -> ExceptionPropertiesUtil.getException(ExceptionConstant.TOKEN_EXPIRED));

    }

    @Override
    public String updateToken(String token, String lastLogin) {
        return Try.of(() -> {
                    JWTVerifier verifier = JWT.require(Algorithm.HMAC256(secret)).build();
                    DecodedJWT jwt = verifier.verify(token);
                    String date = jwt.getClaim("date").asString();
                    UserDTO userDTO = JsonFormatUtil.readFromJsonString(date, UserDTO.class);
                    //跟换登入记录
                    userDTO.setLastLogin(lastLogin);
                    return sign(userDTO);
                }).onFailure(e -> log.error(ExceptionPropertiesUtil.getMsg(ExceptionConstant.TOKEN_EXPIRED)))
                .getOrElseThrow(() -> ExceptionPropertiesUtil.getException(ExceptionConstant.TOKEN_EXPIRED));
    }

    @Override
    public String signFile(String fileId) {
        //过期时间
        Date expireDate = new Date(System.currentTimeMillis() + fileExpireTime * 1000);

        Map<String, Object> map = new HashMap<>();
        map.put("alg", "HS256");
        map.put("typ", "JWT");

        return JWT.create()
                .withHeader(map)                    //添加头部
                //可以把数据存在claim中
                .withClaim("date", fileId)
                .withExpiresAt(expireDate)          //超时设置,设置过期的日期
                .withIssuedAt(new Date())           //签发时间
                .sign(Algorithm.HMAC256(secret));
    }

    @Override
    public String unSignFile(String token) {
        return Try.of(() -> {
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(secret)).build();
            DecodedJWT jwt = verifier.verify(token);
            return jwt.getClaim("date").asString();
        }).onFailure((e) -> {
            log.error(ExceptionPropertiesUtil.getMsg(ExceptionConstant.FILE_TOKEN_EXPIRED));
        }).getOrElseThrow(() -> ExceptionPropertiesUtil.getException(ExceptionConstant.FILE_TOKEN_EXPIRED));
    }
}
